package MAIN;

import javax.swing.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
//笔试强训第36天
//选择题
/*如果将固定块大小的文件系统中的块大小设置大一些，会造成更好的磁盘吞吐量和更差的磁盘空间利用率
* 文件是按块存储的，如果块大小设置的大一些，读取的时候一次性读取的就更多，磁盘吞吐量提升，但是文件可能
* 不能占满整个块，导致利用率下降*/
/*进程的四个基本特征：并发性，动态性，独立性，异步性
* 并发性：指多个进化成提示同存在于内存中，且子一段时间内同时执行，并发性是进程的重要特征，同时也是
* 操作系统的重要特征。      动态性：进程的是指是进程实体的一次执行过程，因此，动态性是进程最基本的特征
* 独立性：进程实体是一个独立运行，独立分配资源和独立接受调度的基本单位
* 异步性: 指进程按各自独立的，不可阈值的速度向前推进，或者说实体按异步方式运行*/
/*等待队列：用于使线程等待某一特定的事件发生而无需频繁的轮询，进程在等待期间睡眠，在某事件发生时由内核唤醒
* 作业后备队列：操作系统首先从外存的后备队列中选取某些作业调入内存，并为他们创建线程，分配必要的资源，然后
* 再将新创建的进程插入到就绪队列，准备执行*/
/*设置Cache的理论基础时程序访问的局部性原理。程序访问的局部性原理时一个程序在运行的某一段时段，它
* 访问的代码或者数据大部分时集中在某一块区域的，此时就可以把这连续的一块或者一两块区域放到缓存中
* Cache和主存没有关系，Cache的地址和主存的地址时两码事，不统一编址，也没有从属关系
* Cache的功能都是由硬件实现的，对程序猿是透明的*/
/*内存抖动是指页面的频繁更换，导致整个系统效率急剧下降，这个现象称为内存抖动，抖动一般是内存 分配
* 算法不好，内存太小引起或者程序的算法不佳引起的页面频繁从内存调入和调出*/
/*响应事件是任务到达和任务开始被处理（响应）之间的时间  周转时间：是到达和处理结束的时间*/
/*实时调度算法：指系统能够在限定的响应时间内体哦概念股所需水平的服务，如果系统的时间约束条件得不到满足
* 将会发生系统错误*/
/*短任务优先算法：执行时间段的任务优先执行*/
/*时间轮转算法：由系统调度就绪队列中的进程，每个进程分配一段时间片，利用时钟中断进行周期性切换，属于抢占式
* 算法*/
/*先来先服务算法：按照先后顺序进行调度*/
/*在所有进程都几乎同时到达时，采用段任务优先调度算法的平均等待时间，平均周转时间最少*/
/*wait()指的是释放当前持有的锁，让当前线程进入等待*/
/*页的划分是操作系统做的*/
/*系统进入死锁必须满足四个条件：互斥，循环等待，不剥夺，请求和保持，所有的进程都挂起，并不表示这些
* 进程之间由资源调用和循环等待的关系，有些进程定时器结束后可能自动唤醒*/
/*静态优先级：在进程执行的时候就已经设置好了，设置好了之后在进程执行的过程中是不能改变开始设定的优先级的
* 所以：进程优先数是进程调度的重要依据，不是必须根据进程运行情况动态改变，还有静态优先级*/
/*程序调优： 改善数据访问方式以提升缓存命中率，此时就不用再去数据库中拿数据了，直接在缓存中拿数据
* 利用数据库连接池替代直接的数据库访问，就是在和数据库建立连接的时候，初始化的时候就创建一定数量的
* 数据库连接，之后在访问数据库的时候，此时就不用再进行创建连接了，数据库连接池中创建的连接是可以反复使用的
* 利用迭代替代递归：1.迭代，2.尾递归
* 共享冗余数据提高访问效率：大家都是读自己的数据，此时就是访问你的我访问我的，此时的数据可能在内存中
* 的不同的块中或者是外设中，但是共享了就是存在同一块内存中了*/

//
class Rational {
    private long numerator; //分子
    private long denominator; //分母
    private long integer; //整数
    private boolean negetive; //负数
    private boolean isZero; //分母为0
    private long totalNumerator; //参与运算的分子：整数+ 原来分子
    public static long paraseNumerator(String s) {
        //只需从字符串中将分子截取出来
        return Long.parseLong(s.substring(0, s.indexOf('/')));
    }
    public static long paraseDenominator(String s) {
        //只需从字符串中将分母截取出来
        return Long.parseLong(s.substring(s.indexOf('/') + 1), s.length());
    }

    public Rational(long n, long d) {//n为分子，d为分母
        if (0 == d) {//在输入的时候分母永远不可能为0，但是经过计算之后分母可能会为0
            isZero = true;
            return;
        }
        //如果分子小于0，表示为负数
        if (n < 0) negetive = !negetive;
        //在输入的时候，分母永远不可能小于0，但是经过计算之后分母也可能会小于0
        if (d < 0) negetive = !negetive;
        //如果输入是假分数，需要将其调整为真分数 比如： 5 / 3 ===》 1 2/3
        integer = n / d;
        numerator = n - integer * d;
        denominator = Math.abs(d);

        //如果分数不是最简的形式，需要将其约分成最简的形式，比如： 10/15 ---> 2/3
        //在分子和分母的基础之上分别除以分子和分母的最大公约数
        if (numerator > 1 || numerator < -1) {//分子如果是1或-1的话不能进行约分
            long gcd = calcGCD(Math.abs(numerator), denominator);
            if (gcd > 0) {
                numerator /= gcd;
                denominator /= gcd;
            }
        }
        totalNumerator = numerator + integer*denominator;
    }
    //求最大公约数：采用辗转相除法
    private long calcGCD(long a, long b) {
        if (0 == b) return a;
        return calcGCD(b, a % b);
    }

    public Rational Add(Rational r) {
        long n = totalNumerator * r.denominator + denominator * r.totalNumerator;
        long d = denominator * r.denominator;
        return new Rational(n, d);
    }
    public Rational Sub(Rational r) {
        long n = totalNumerator * r.denominator - denominator * r.totalNumerator;
        long d = denominator * r.denominator;
        return new Rational(n, d);
    }
    public Rational Mul(Rational r) {
        long n = totalNumerator * r.denominator;
        long d = denominator * r.denominator;
        return new Rational(n, d);
    }
    public Rational Div(Rational r) {
        long n = totalNumerator * r.denominator;
        long d = denominator * r.totalNumerator;
        return new Rational(n, d);
    }

    public String toString() {
        StringBuffer s = new StringBuffer();
        //分母为0，输出Inf
        if (isZero) {
            s.append("Inf");
            return new String(s);
        }

        if (0 == integer && 0 == numerator) {
            s.append("0");
            return new String(s);
        }
        if (negetive) {
            s.append("(-");
        }
        //输出rational：整数部分 + 分数部分
        //整数部分
        if (0 != integer) {
            s.append(Math.abs(integer));
            //整数部分和分数部分需要使用空格隔开
            if (0 != numerator) {
                s.append(' ');
            }
        }
        //输出分数部分: 可能存在，也可能不存在
        if (0 != numerator) {
            s.append(Math.abs(numerator));
            s.append('/');
            s.append(denominator);
        }
        if (negetive) {
            s.append(')');
        }
        return new String(s);
    }
}
public class Main36 {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        while (scan.hasNext()) {
            //接收一组测试用例
            String s = scan.next();
            Rational r1 = new Rational(Rational.paraseNumerator(s),
                    Rational.paraseDenominator(s));
            s = scan.next();
            Rational r2 = new Rational(Rational.paraseNumerator(s),
                    Rational.paraseDenominator(s));
            //Add Sub Mul Div toString
            System.out.println(r1 + " + " + r2 + " = " + r1.Add(r2));
            System.out.println(r1 + " + " + r2 + " = " + r1.Sub(r2));
            System.out.println(r1 + " + " + r2 + " = " + r1.Mul(r2));
            System.out.println(r1 + " + " + r2 + " = " + r1.Div(r2));

        }
    }
}
